/**
 * 图谱布局工具函数
 * 提供图谱布局相关的辅助函数
 */

/**
 * 创建拖拽行为
 * @param {Object} simulation D3力导向模拟对象
 * @param {boolean} editable 是否可编辑
 * @param {Function} onNodePositionUpdate 节点位置更新回调
 * @returns {Function} 拖拽行为函数
 */
export const createDragBehavior = (simulation, editable, onNodePositionUpdate) => {
  if (!window.d3) return () => {};
  
  const d3 = window.d3;
  
  return d3.drag()
    .on('start', (event, d) => {
      if (!event.active) simulation.alphaTarget(0.3).restart();
      d.fx = d.x;
      d.fy = d.y;
    })
    .on('drag', (event, d) => {
      d.fx = event.x;
      d.fy = event.y;
    })
    .on('end', (event, d) => {
      if (!event.active) simulation.alphaTarget(0);
      if (!editable) {
        d.fx = null;
        d.fy = null;
      } else {
        onNodePositionUpdate?.(d.id, d.fx, d.fy);
      }
    });
};

/**
 * 构建思维导图层次结构
 * @param {Array} nodes 节点数据
 * @param {Array} edges 边数据
 * @returns {Object} 层次结构对象
 */
export const buildMindMapHierarchy = (nodes, edges) => {
  if (!nodes || nodes.length === 0) {
    return null;
  }

  // 如果没有边，创建一个简单的根节点结构
  if (!edges || edges.length === 0) {
    return {
      ...nodes[0],
      level: 0,
      children: nodes.slice(1).map((node, index) => ({
        ...node,
        level: 1,
        children: []
      }))
    };
  }

  // 找到根节点（没有父节点的节点）
  const rootCandidates = nodes.filter(node => 
    !edges.some(edge => edge.target === node.id)
  );
  
  const rootNode = rootCandidates.length > 0 ? rootCandidates[0] : nodes[0];

  // 构建层次结构
  const buildHierarchy = (nodeId, level = 0, visited = new Set()) => {
    if (visited.has(nodeId)) return null;
    visited.add(nodeId);
    
    const node = nodes.find(n => n.id === nodeId);
    if (!node) return null;

    // 查找子节点
    const childEdges = edges.filter(edge => 
      (typeof edge.source === 'object' ? edge.source.id : edge.source) === nodeId
    );
    
    const children = childEdges
      .map(edge => {
        const targetId = typeof edge.target === 'object' ? edge.target.id : edge.target;
        return buildHierarchy(targetId, level + 1, visited);
      })
      .filter(child => child !== null);

    return {
      ...node,
      level,
      children
    };
  };

  const hierarchy = buildHierarchy(rootNode.id);
  
  // 如果构建失败，创建一个简单的平铺结构
  if (!hierarchy || !hierarchy.children || hierarchy.children.length === 0) {
    const remainingNodes = nodes.filter(n => n.id !== rootNode.id);
    return {
      ...rootNode,
      level: 0,
      children: remainingNodes.map((node, index) => ({
        ...node,
        level: 1,
        children: []
      }))
    };
  }

  return hierarchy;
};

/**
 * 扁平化节点层次结构
 * @param {Object} node 层次结构节点
 * @param {Array} result 结果数组
 * @returns {Array} 扁平化的节点数组
 */
export const flattenNodeHierarchy = (node, result = []) => {
  result.push(node);
  if (node.children) {
    node.children.forEach(child => flattenNodeHierarchy(child, result));
  }
  return result;
};

/**
 * 计算节点度数
 * @param {Array} nodes 节点数据
 * @param {Array} edges 边数据
 * @returns {Map} 节点度数映射
 */
export const calculateNodeDegrees = (nodes, edges) => {
  const nodeDegrees = new Map();
  nodes.forEach(node => nodeDegrees.set(node.id, 0));
  edges.forEach(edge => {
    nodeDegrees.set(edge.source, (nodeDegrees.get(edge.source) || 0) + 1);
    nodeDegrees.set(edge.target, (nodeDegrees.get(edge.target) || 0) + 1);
  });
  return nodeDegrees;
};

/**
 * 创建布局
 * @param {string} layoutType 布局类型
 * @param {Array} nodes 节点数据
 * @param {Array} edges 边数据
 * @param {string} graphType 图谱类型
 * @param {number} width 宽度
 * @param {number} height 高度
 * @param {Object} settings 布局设置
 * @returns {Object} 布局对象
 */
export const createLayout = (layoutType, nodes, edges, graphType, width, height, settings = {}) => {
  if (!window.d3) return null;
  
  const d3 = window.d3;
  
  switch (layoutType) {
    case 'force':
      return createForceLayout(nodes, edges, width, height, settings, d3);
    case 'circular':
      return createCircularLayout(nodes, width, height, settings);
    case 'hierarchical':
      return createHierarchicalLayout(nodes, edges, width, height, settings, d3);
    case 'grid':
      return createGridLayout(nodes, width, height, settings);
    case 'radial':
      return createRadialLayout(nodes, edges, width, height, settings);
    case 'tree':
      return createTreeLayout(nodes, edges, width, height, settings, d3);
    default:
      return createForceLayout(nodes, edges, width, height, settings, d3);
  }
};

// 力导向布局
const createForceLayout = (nodes, edges, width, height, settings, d3) => {
  const defaultSettings = {
    linkDistance: 100,
    linkStrength: 0.5,
    chargeStrength: -300,
    centerStrength: 0.1,
    collisionRadius: 30
  };
  
  const mergedSettings = { ...defaultSettings, ...settings };
  
  const simulation = d3.forceSimulation(nodes)
    .force('link', d3.forceLink(edges)
      .id(d => d.id)
      .distance(mergedSettings.linkDistance)
      .strength(mergedSettings.linkStrength))
    .force('charge', d3.forceManyBody()
      .strength(mergedSettings.chargeStrength))
    .force('center', d3.forceCenter(width / 2, height / 2)
      .strength(mergedSettings.centerStrength))
    .force('collision', d3.forceCollide()
      .radius(mergedSettings.collisionRadius))
    .force('x', d3.forceX(width / 2).strength(0.05))
    .force('y', d3.forceY(height / 2).strength(0.05));

  return simulation;
};

// 环形布局
const createCircularLayout = (nodes, width, height, settings) => {
  const defaultSettings = {
    radius: 0.4,
    startAngle: 0,
    endAngle: 2 * Math.PI
  };
  
  const mergedSettings = { ...defaultSettings, ...settings };
  const radius = mergedSettings.radius * Math.min(width, height);
  const centerX = width / 2;
  const centerY = height / 2;
  const startAngle = mergedSettings.startAngle;
  const endAngle = mergedSettings.endAngle;
  const angleRange = endAngle - startAngle;
  
  return nodes.map((node, index) => {
    const angle = startAngle + (index / nodes.length) * angleRange;
    return {
      ...node,
      x: centerX + radius * Math.cos(angle),
      y: centerY + radius * Math.sin(angle),
      fx: centerX + radius * Math.cos(angle),
      fy: centerY + radius * Math.sin(angle)
    };
  });
};

// 层次布局
const createHierarchicalLayout = (nodes, edges, width, height, settings, d3) => {
  const defaultSettings = {
    direction: 'vertical'
  };
  
  const mergedSettings = { ...defaultSettings, ...settings };
  const isVertical = mergedSettings.direction !== 'horizontal';
  
  try {
    // 构建层次结构
    const hierarchy = d3.stratify()
      .id(d => d.id)
      .parentId(d => {
        const parentEdge = edges.find(e => e.target === d.id);
        return parentEdge ? parentEdge.source : null;
      })(nodes.filter(n => n.id));

    const treeLayout = d3.tree()
      .size(isVertical ? [width - 100, height - 100] : [height - 100, width - 100]);

    const root = treeLayout(hierarchy);
    
    return root.descendants().map(d => ({
      ...d.data,
      x: isVertical ? d.x + 50 : d.y + 50,
      y: isVertical ? d.y + 50 : d.x + 50,
      fx: isVertical ? d.x + 50 : d.y + 50,
      fy: isVertical ? d.y + 50 : d.x + 50
    }));
  } catch (error) {
    console.error("无法构建层次结构，回退到网格布局", error);
    return createGridLayout(nodes, width, height, settings);
  }
};

// 网格布局
const createGridLayout = (nodes, width, height, settings) => {
  const defaultSettings = {
    cols: 'auto',
    cellWidth: 100,
    cellHeight: 100
  };
  
  const mergedSettings = { ...defaultSettings, ...settings };
  const cols = mergedSettings.cols === 'auto' ? Math.ceil(Math.sqrt(nodes.length)) : mergedSettings.cols;
  const cellWidth = mergedSettings.cellWidth || (width - 100) / cols;
  const cellHeight = mergedSettings.cellHeight || (height - 100) / Math.ceil(nodes.length / cols);
  
  return nodes.map((node, index) => {
    const row = Math.floor(index / cols);
    const col = index % cols;
    return {
      ...node,
      x: 50 + col * cellWidth + cellWidth / 2,
      y: 50 + row * cellHeight + cellHeight / 2,
      fx: 50 + col * cellWidth + cellWidth / 2,
      fy: 50 + row * cellHeight + cellHeight / 2
    };
  });
};

// 辐射布局
const createRadialLayout = (nodes, edges, width, height, settings) => {
  const defaultSettings = {
    radius: 0.4,
    levelSeparation: 80
  };
  
  const mergedSettings = { ...defaultSettings, ...settings };
  const centerX = width / 2;
  const centerY = height / 2;
  const levelSeparation = mergedSettings.levelSeparation;
  
  // 找到中心节点（连接最多的节点）
  const nodeDegrees = calculateNodeDegrees(nodes, edges);
  
  const centerNode = nodes.reduce((max, node) => 
    (nodeDegrees.get(node.id) || 0) > (nodeDegrees.get(max.id) || 0) ? node : max, 
    nodes[0]
  );

  // BFS分层
  const levels = new Map();
  const visited = new Set();
  const queue = [centerNode.id];
  levels.set(centerNode.id, 0);
  visited.add(centerNode.id);

  while (queue.length > 0) {
    const current = queue.shift();
    const currentLevel = levels.get(current);
    
    edges.forEach(edge => {
      const neighbor = edge.source === current ? edge.target : 
                      edge.target === current ? edge.source : null;
      if (neighbor && !visited.has(neighbor)) {
        visited.add(neighbor);
        levels.set(neighbor, currentLevel + 1);
        queue.push(neighbor);
      }
    });
  }

  // 计算位置
  const levelGroups = new Map();
  levels.forEach((level, nodeId) => {
    if (!levelGroups.has(level)) levelGroups.set(level, []);
    levelGroups.get(level).push(nodeId);
  });

  return nodes.map(node => {
    const level = levels.get(node.id) || 0;
    const levelNodes = levelGroups.get(level) || [];
    const index = levelNodes.indexOf(node.id);
    const radius = level === 0 ? 0 : level * levelSeparation;
    const angle = levelNodes.length > 1 ? (index / levelNodes.length) * 2 * Math.PI : 0;
    
    return {
      ...node,
      x: centerX + radius * Math.cos(angle),
      y: centerY + radius * Math.sin(angle),
      fx: centerX + radius * Math.cos(angle),
      fy: centerY + radius * Math.sin(angle)
    };
  });
};

// 树形布局
const createTreeLayout = (nodes, edges, width, height, settings, d3) => {
  const defaultSettings = {
    direction: 'vertical'
  };
  
  const mergedSettings = { ...defaultSettings, ...settings };
  const isHorizontal = mergedSettings.direction === 'horizontal';
  
  try {
    const root = d3.stratify()
      .id(d => d.id)
      .parentId(d => {
        const parentEdge = edges.find(e => e.target === d.id);
        return parentEdge ? parentEdge.source : null;
      })(nodes);

    const treeLayout = d3.tree()
      .size(isHorizontal ? [height - 100, width - 100] : [width - 100, height - 100]);

    const treeRoot = treeLayout(root);
    
    return treeRoot.descendants().map(d => ({
      ...d.data,
      x: isHorizontal ? d.y + 50 : d.x + 50,
      y: isHorizontal ? d.x + 50 : d.y + 50,
      fx: isHorizontal ? d.y + 50 : d.x + 50,
      fy: isHorizontal ? d.x + 50 : d.y + 50
    }));
  } catch (error) {
    console.error("无法构建树结构，回退到层次布局", error);
    return createHierarchicalLayout(nodes, edges, width, height, settings, d3);
  }
};